import vnnlp
import random
import math
import codecs
import inspect
import os
import nltk.metrics as metrics
import random

NUMFITCASE = 20
NUMFITTEST = 10
PI = 4.1416
class Summarization:
    '''
    Symbolic regression
    '''
    def __init__(self, rand):
        '''
        fitcase: is list of features [x1, x2, x3, x4]
        fitcase[i][j][k]:   document i-th;
                            sentence j-th in document i-th
                            feature k-th of sentence
        '''
        self.fitcase = []#for training
        self.fittest = []#for testing
        self.ref_fitcase = [] #list index of extracted sentence for training
        self.ref_fittest = [] # for testing
        self.SuccPredicate = False
        self.term = vnnlp.pygp.Term(rand)
        self.LoadTerm()
        self.load_ref()
        self.SetFitCase()

    def LoadTerm(self):
        print 'Loading terms...'
        self.term.AddTerm("ADD", 2)
        self.term.AddTerm("SUB", 2)
        self.term.AddTerm("DIV", 2)
        self.term.AddTerm("MUL", 2)
##        self.term.AddTerm("SIN", 1)
##        self.term.AddTerm("COS", 1)
##        self.term.AddTerm("EP", 1)
##        self.term.AddTerm("X", 0)
        self.term.AddTerm("X1", 0)
        self.term.AddTerm("X2", 0)
        self.term.AddTerm("X3", 0)
        self.term.AddTerm("X4", 0)        
        self.term.Swap(100)
        print 'Done!'

    def load_ref(self):
        dataset = inspect.stack()[0][1]
        ref_index_file = os.path.normpath(os.path.join(dataset, "..","dataset\\ref_index.txt"))
        f = codecs.open(ref_index_file, 'r', encoding = 'utf-8')
        lines = f.readlines()
        i = 0
        for line in lines: #for each document
            temp = line.split(' ')
            index_sen = [int(index) for index in temp]
            if i < NUMFITCASE:
                self.ref_fitcase.append(index_sen)
            else:
                self.ref_fittest.append(index_sen)
            i += 1
        
    def SetFitCase(self):
        '''
        1. read feature file
        2. fill features into fitcase or fittest
        '''
        dataset = inspect.stack()[0][1]
        dataset = os.path.normpath(os.path.join(dataset, "..","dataset\\feature\\"))
        #dataset = '/dataset/feature/'        
        for i in range(1, NUMFITCASE + NUMFITTEST+1):
            filename = 'test' + str(i) + '.ct'
            pathfile = os.path.join(dataset, filename)
            f = codecs.open(pathfile, 'r', encoding='utf-8')
            lines = f.readlines()
            doc_feature = []#set of features in a document
            for line in lines: #for each sentence
                temp = line.split(' ')
                x = [float(temp[0]), float(temp[1]), float(temp[2]), float(temp[3])]
                doc_feature.append(x)
            if i < NUMFITCASE + 1:
                self.fitcase.append(doc_feature)
            else:
                self.fittest.append(doc_feature)
        
    def Compute(self, node, x):
        '''
        compute the function (in tree form) with given input
        @node: tree root
        @x: value of x [X1, X2, X3, X4]
        '''
        if node.name == '1':
            return 1        
        if node.name == 'X1':
            return x[0]
        if node.name == 'X2':
            return x[1]
        if node.name == 'X3':
            return x[2]
        if node.name == 'X4':
            return x[3]
        elif node.name == 'PI':
            return PI
        else:
            if node.name == 'ADD':
                l = self.Compute(node.children[0], x)
                r = self.Compute(node.children[1], x)
                return l + r
            elif node.name == 'SUB':
                l = self.Compute(node.children[0], x)
                r = self.Compute(node.children[1], x)
                return l - r
            elif node.name == 'MUL':
                l = self.Compute(node.children[0], x)
                r = self.Compute(node.children[1], x)
                return l * r
            elif node.name == 'DIV':
                l = self.Compute(node.children[0], x)
                r = self.Compute(node.children[1], x)
                if r == 0:
                    return 1
                else:
                    return l / r
            elif node.name == 'SIN':
                l = self.Compute(node.children[0], x)
                try:
                    return math.sin(l)
                except ValueError:
                    return math.exp(700)
            elif node.name == 'COS':
                l = self.Compute(node.children[0], x)
                try:
                    return math.cos(l)
                except ValueError:
                    return math.exp(700)
            elif node.name == 'EP':
                l = self.Compute(node.children[0], x)
                try:
                    return math.exp(l)
                except OverflowError:
                    if l > 0:
                        return math.exp(700)
                    else:
                        return -math.exp(700)
            elif node.name == 'LOG':
                l = self.Compute(node.children[0], x)
                if l == 0:
                    return 0
                else:
                    return math.log10(math.fabs(l))
            elif node.name == "SQRT":
                l = self.Compute(node.children[0], x)
                try:
                    return math.sqrt(math.fabs(l))
                except OverflowError:
                    if l > 0:
                        return math.exp(700)
                    else:
                        return -math.exp(700)

    def ComputeRF(self, individual):
        '''
        Compute the raw fitness for an individual
        '''
        #print 'computeRF...'
        summ = 0
        hit  = 0
        for i in range (NUMFITCASE):
            num_sen = len(self.fitcase[i])
            sen_score = []
            #compute score of each sentence in document i
            for j in range(num_sen):
                ft = self.Compute(individual.chrom, self.fitcase[i][j])
                sen_score.append(ft)
            #extracted sentences
            num_sen_ext = len(self.ref_fitcase[i])
            max_index = [] #index sentences that have largest score
            for k in range(num_sen_ext):
                #get index of max score
                index = sen_score.index(max(sen_score))
                #append into max_index
                max_index.append(index)
                #remove index from score
                sen_score.pop(index)
            #compute f-measure
            ref_set = set(self.ref_fitcase[i])
            test_set = set(max_index)
            f_measure = metrics.f_measure(ref_set, test_set)
            summ += f_measure
        return 1 - summ/NUMFITCASE

    def ComputeFT(self, individual):
        '''
        Compute the raw fitness for an individual
        '''
        #print 'computeRF...'
        summ = 0
        hit  = 0
        for i in range (NUMFITTEST):
            num_sen = len(self.fittest[i])
            sen_score = []
            #compute score of each sentence in document i
            for j in range(num_sen):
                ft = self.Compute(individual.chrom, self.fittest[i][j])
                sen_score.append(ft)
            #extracted sentences
            num_sen_ext = len(self.ref_fittest[i])
            max_index = [] #index sentences that have largest score
            for k in range(num_sen_ext):
                #get index of max score
                index = sen_score.index(max(sen_score))
                #append into max_index
                max_index.append(index)
                #remove index from score
                sen_score.pop(index)
            #compute f-measure
            ref_set = set(self.ref_fittest[i])
            test_set = set(max_index)
            f_measure = metrics.f_measure(ref_set, test_set)
            summ += f_measure
        return 1 - summ/NUMFITTEST
 
#test
if __name__ == '__main__':
    rand = random.Random()
    summa = Summarization(rand)
    summa.load_ref()
    print 'ref_fitcase: ', len(summa.ref_fitcase)
    print 'ref_fittest: ', len(summa.ref_fittest)
